﻿// Copyright 2007-2009 Stuart Caborn, Alex Scordellis
//  
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
//  use this file except in compliance with the License. You may obtain a copy of
//  the License at
//  
//  http://www.apache.org/licenses/LICENSE-2.0
//  
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
//  License for the specific language governing permissions and limitations under
//  the License.
// 

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;

namespace NSynthesis
{
    [Serializable]
    public class Report
    {
        [Obsolete("For use by serializer only!", true)]
        public Report() { }

        public Report(IEnumerable<MockedMethodCall> missingMethods,
                      IEnumerable<MockedMethodCall> mockedMethods,
                      IEnumerable<RealMethodCall> realMethods)
        {
            Errors = (from missingMethod in missingMethods
                      from realCall in missingMethod.RealImplementations
                      where !realCall.HasBeenCalled
                      select new ErrorDescription(missingMethod.Description, realCall.Description)).ToList();

            Errors.AddRange(
                from missingMethod in missingMethods
                where !missingMethod.RealImplementations.Any()
                select new ErrorDescription(missingMethod.Description, null));

            MockedMethods = (from method in mockedMethods
                             select new MockInfo
                                        {
                                            MockMethodName = method.Description,
                                            RealMethodCalls =
                                                method.RealImplementations.Select(productionMethod => productionMethod.Description).ToList()
                                        }).ToList();

            RealMethods = realMethods.Select(call => call.Description).ToList();
        }

        [XmlElement("rm")]
        public List<string> RealMethods { get; set; }

        [XmlElement("mm")]
        public List<MockInfo> MockedMethods { get; set; }

        [XmlElement("e")]
        public List<ErrorDescription> Errors { get; set; }

        private static string DefaultPath
        {
            get { return "synthesis.xml"; }
        }

        public bool HasErrors { get { return Errors.Count > 0; } }

        public static Report Load(string path)
        {
            var serializer = new XmlSerializer(typeof (Report));
            using (var stream = new FileStream(path, FileMode.Open))
            {
                return (Report) serializer.Deserialize(stream);
            }
        }

        public void Save(string path)
        {
            var serializer = new XmlSerializer(typeof (Report));
            using (var stream = new FileStream(path, FileMode.Create))
            {
                serializer.Serialize(stream, this);
            }
        }

        public void Save() { Save(DefaultPath); }

        #region Nested type: ErrorDescription

        [Serializable]
        public class ErrorDescription
        {
            [Obsolete("For use by serializer only!", true)]
            public ErrorDescription() { }

            public ErrorDescription(string mockedMethod, string missingMethod)
            {
                MockedMethod = mockedMethod;
                MissingMethod = missingMethod;
            }

            [XmlAttribute("mo")]
            public string MockedMethod { get; set; }

            [XmlAttribute("mi")]
            public string MissingMethod { get; set; }
        }

        #endregion

        #region Nested type: MockInfo

        public class MockInfo
        {
            [XmlAttribute("n")]
            public string MockMethodName { get; set; }

            [XmlAttribute("h")]
            public int Hits{ get; set; }

            [XmlAttribute("rc")]
            public List<string> RealMethodCalls { get; set; }
        }

        #endregion
    }
}